using System;
using System.IO;
using System.Xml;
using NetActive.Notifications.Services.WP7.Interfaces;

namespace NetActive.Notifications.Services.WP7
{
    public class TileNotification : NotificationBase
    {
        /// <summary>
        /// Constructor leaving current tile values intact.
        /// </summary>
        /// <param name="clientNotificationChannelUri">Client notification channel Uri.</param>
        public TileNotification(Uri clientNotificationChannelUri)
            : this(clientNotificationChannelUri, false)
        {
        }

        /// <summary>
        /// Constructor clearing all tile value except the front background image.
        /// </summary>
        /// <param name="clientNotificationChannelUri">Client notification channel Uri.</param>
        /// <param name="clearAllValues">If TRUE, by default clears all values but the front background image.</param>
        public TileNotification(Uri clientNotificationChannelUri, bool clearAllValues)
            : base(clientNotificationChannelUri)
        {
            if (!clearAllValues) return;

            Front.Count = -1;
            Front.Title = null;
            Back.BackgroundImageUri = null;
            Back.Title = null;
            Back.Content = null;
        }

        /// <summary>
        /// Constructor leaving current tile values intact, setting the front count value as specified.
        /// </summary>
        /// <param name="clientNotificationChannelUri">Client notification channel Uri.</param>
        /// <param name="frontCount">Count for the front of the tile.</param>
        public TileNotification(Uri clientNotificationChannelUri, int frontCount)
            : base(clientNotificationChannelUri)
        {
            Front.Count = frontCount;
            Front.Title = string.Empty;
            Back.BackgroundImageUri = string.Empty;
            Back.Title = string.Empty;
            Back.Content = string.Empty;
        }

        /// <summary>
        /// Gets a reference to the front side of the tile.
        /// </summary>
        public readonly TileNotificationFront Front = new TileNotificationFront();

        /// <summary>
        /// Gets a reference to the back side of the tile.
        /// </summary>
        public readonly TileNotificationBack Back = new TileNotificationBack();

        /// <summary>
        /// Gets the string representing the target header for this notification type.
        /// </summary>
        public override string TargetHeader
        {
            get { return "token"; }
        }

        /// <summary>
        /// Method used to return a byte representation of the notification ready to send to the Push Notification Services.
        /// </summary>
        /// <returns>Byte representation of the notification.</returns>
        public override byte[] GetBytes()
        {
            using (var stream = new MemoryStream())
            {
                var settings = GetSettings();

                using (var writer = XmlWriter.Create(stream, settings))
                {
                    writer.WriteStartDocument();
                    writer.WriteStartElement("wp", "Notification", "WPNotification");
                    writer.WriteStartElement("wp", "Tile", "WPNotification");
                    writer.WriteStartElement("wp", "BackgroundImage", "WPNotification");
                    writer.WriteValue(Front.BackgroundImageUri);
                    writer.WriteEndElement();
                    
                    writer.WriteStartElement("wp", "Count", "WPNotification");
                    if(Front.Count == -1)
                        writer.WriteAttributeString("Action", "Clear");
                    else
                        writer.WriteValue(Front.Count);
                    writer.WriteEndElement();
                    
                    writer.WriteStartElement("wp", "Title", "WPNotification");
                    if (Front.Title == null)
                        writer.WriteAttributeString("Action", "Clear");
                    else
                        writer.WriteValue(Front.Title);
                    writer.WriteEndElement();
                    
                    writer.WriteStartElement("wp", "BackBackgroundImage", "WPNotification");
                    if (Back.BackgroundImageUri == null)
                        writer.WriteAttributeString("Action", "Clear");
                    else
                        writer.WriteValue(Back.BackgroundImageUri);
                    writer.WriteEndElement();
                    
                    writer.WriteStartElement("wp", "BackTitle", "WPNotification");
                    if (Back.Title == null)
                        writer.WriteAttributeString("Action", "Clear");
                    else
                        writer.WriteValue(Back.Title);
                    writer.WriteEndElement();
                    
                    writer.WriteStartElement("wp", "BackContent", "WPNotification");
                    if (Back.Content == null)
                        writer.WriteAttributeString("Action", "Clear");
                    else
                        writer.WriteValue(Back.Content);
                    writer.WriteEndElement();
                    
                    writer.WriteEndElement();
                    writer.WriteEndDocument();
                    writer.Close();

                    var payload = stream.ToArray();

                    return payload;
                }
            }
        }

        /// <summary>
        /// Returns and integer value representing the selected <seealso cref="INotification.DeliveryInterval"/>.
        /// </summary>
        /// <returns>Integer value representing the delivery interval.</returns>
        public override int GetDeliveryInterval()
        {
            if (DeliveryInterval == NotificationDeliveryInterval.Within450Seconds) return 11;
            return DeliveryInterval == NotificationDeliveryInterval.Within900Seconds ? 21 : 1;
        }

        #region Helper Classes For Tiles

        /// <summary>
        /// One side of a Tile.
        /// </summary>
        public class TileNotificationSide
        {
            public string Title { get; set; }

            public string BackgroundImageUri { get; set; }
        }

        /// <summary>
        /// The front of a Tile.
        /// </summary>
        public class TileNotificationFront : TileNotificationSide
        {
            public int Count { get; set; }
        }

        /// <summary>
        /// The back of a Tile.
        /// </summary>
        public class TileNotificationBack : TileNotificationSide
        {
            public string Content { get; set; }
        }

        #endregion
    }
}